import random
from Genotype import Genotype
class GAAlg:
    
    
    def __init__(self, initIndividualNum = 1000, offspringSize = 1000):
        self.individualArray = []
        self.matingPool = []
        self.fitnessArray = []
        self.geneSize = 4
        self.trafficLightNum = 10
        self.populationSize = 1000
        self.offspringSize = 1000
        self.parentSize = 100
    
        #termination criterion
        self.fitnessValue = 0
        self.maxIteration = 0
        
        for i in range(0, initIndividualNum) : #fill the inidividualArray with initial value
            self.individualArray.append(Genotype(self.trafficLightNum))
            self.fitnessArray.append(0)
        self.populationSize = initIndividualNum;
        self.offspringSize = offspringSize;
            
            
            
    def roulette(self):
        #initialize
        self.matingPool = []
        for i in range(0, self.populationSize) :
            if i == 0 :
                self.fitnessArray[i] = self.individualArray[i].evaluateFitness()
            else : 
                self.fitnessArray[i] += self.individualArray[i].evaluateFitness()
        #convert absolute value to proportion
        for i in range(0, self.populationSize) :
            self.fitnessArray[i] = self.fitnessArray[i] / self.fitnessArray[self.populationSize - 1]
        startNum = 0;
        while(startNum < self.parentSize) :
            selectRate = random.random();
            shouldSelectIndex = 0
            for i in range(0, self.populationSize) :
                if self.fitnessArray[i] > selectRate :
                    shouldSelectIndex = i
                    break
            self.matingPool.append(shouldSelectIndex)
            startNum = startNum + 1
            
    
    
    def reproduce(self):
        totalOffspringNum = 0
        while(totalOffspringNum < self.offspringSize) :
            firstParentIndex = random.randint(0, self.offspringSize)
            secondParentIndex = random.randint(0, self.offspringSize)
            if firstParentIndex != secondParentIndex :
                totalOffspringNum += 2
                crossedChildren = self.individualArray[firstParentIndex].onePointCrossover(self.individualArray[secondParentIndex])
                self.individualArray.append(crossedChildren[0])
                self.individualArray.append(crossedChildren[1])
                
    
    
    def compare(self, genotype):
        return genotype.evaluateFitness()
        
    def selectSurvivor(self):
        #sorted(self.individualArray, key = self.compare) #for the value in ascending order
        #use the generational strategy
        while len(self.individualArray) > self.populationSize :
            del self.individualArray[0]
        
    
    def hasReachedTermination(self, fitnessValue = -1, maxIteration = -1):
        if fitnessValue > 0:
            if self.fitnessValue > fitnessValue :
                return True
        if self.maxIteration > 0 :
            if self.maxIteration > maxIteration :
                return True
        return False
    
    def findTheBestFitness(self):
        maxValue = 0
        for i in range(0, len(self.fitnessArray)) :
            if self.fitnessArray[i] > maxValue :
                maxValue = self.fitnessArray[i]
        return maxValue
                
                
    def execute(self):
        self.roulette()
        self.maxFitness = self.findTheBestFitness() 
        self.maxIteration = self.maxIteration + 1
        self.reproduce()
        self.selectSurvivor()
        return self.maxFitness